package io.nutz.nutzsite;

import com.alibaba.fastjson.JSON;
import io.nutz.nutzsite.common.base.Globals;
import io.nutz.nutzsite.common.base.Result;
import io.nutz.nutzsite.common.manager.AsyncManager;
import io.nutz.nutzsite.common.mvc.MyActionChainMaker;
import io.nutz.nutzsite.common.utils.DateUtils;
import io.nutz.nutzsite.common.utils.ShiroUtils;
import io.nutz.nutzsite.common.utils.StringUtils;
import io.nutz.nutzsite.common.utils.TreeUtils;
import io.nutz.nutzsite.module.acm.services.SolutionService;
import io.nutz.nutzsite.module.sys.models.*;
import io.nutz.nutzsite.module.sys.services.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ThreadContext;
import org.nutz.boot.NbApp;
import org.nutz.conf.NutConf;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.util.Daos;
import org.nutz.el.opt.RunMethod;
import org.nutz.el.opt.custom.CustomMake;
import org.nutz.integration.quartz.QuartzJob;
import org.nutz.integration.quartz.QuartzManager;
import org.nutz.integration.shiro.ShiroSessionProvider;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Encoding;
import org.nutz.lang.Mirror;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.Mvcs;
import org.nutz.mvc.annotation.*;
import org.nutz.plugins.slog.annotation.Slog;
import org.quartz.Scheduler;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.management.ManagementFactory;
import java.nio.charset.Charset;
import java.sql.Driver;
import java.sql.DriverManager;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;

/**
 * @author haiming
 */
@IocBean(create = "init", depose = "depose")
@Modules(packages = "io.nutz")
@IocBy(args="*slog")
@Localization(value = "locales/", defaultLocalizationKey = "zh-CN")
@ChainBy(type= MyActionChainMaker.class, args={})
@SessionBy(ShiroSessionProvider.class)
public class MainLauncher {
    private static final Log log = Logs.get();

    @Inject("refer:$ioc")
    private Ioc ioc;

    @Inject
    protected Dao dao;

    @Inject
    protected PropertiesProxy conf;

    @Inject
    private UserService userService;
    @Inject
    private MenuService menuService;
    @Inject
    private ImageService imageService;
    @Inject
    DeptService deptService;
    @Inject
    MytaskService mytaskService;
    @Inject
	private SolutionService solutionService;
    /**
     * 启动方法
     * @param args
     */
    public static void main(String[] args) {
        new NbApp().setArgs(args).setPrintProcDoc(true).run();
        //是否启用FastClass机制,会提高反射的性能,如果需要热部署,应关闭. 性能影响低于10%
        NutConf.USE_FASTCLASS = true;
    }


    @At({"/adm"})
    @Ok("re")
    public String index(HttpServletRequest req) {
        User user = ShiroUtils.getSysUser();
        if (!ShiroUtils.isAuthenticated()) {
            return "th:/login.html";
        }
        user =userService.fetchLinks(user,"dept|image");
        req.setAttribute("user", user);
        List<Menu> menuList = menuService.getMenuList(user.getId());
        req.setAttribute("menus", TreeUtils.getChildPerms(menuList, "0"));
        req.setAttribute("now0", DateUtils.getDateTime());
        return "th:/index.html";
    }
    @At({"/","/index"})
    @Ok("re")
    public String index3(HttpServletRequest req) {
        User user = ShiroUtils.getSysUser();
        if (!ShiroUtils.isAuthenticated())
        {
            return "th:/login.html";//th:/kc.html
        }
        user =userService.fetchLinks(user,"dept|image");
        req.setAttribute("user", user);
        List<Menu> menuList = menuService.getMenuList(user.getId());
        req.setAttribute("menus", TreeUtils.getChildPerms(menuList, "0"));
        req.setAttribute("now0", DateUtils.getDateTime());
        return "th:/index.html";
    }
    /***
     * 考生进考场
     * @param req
     * @return
     */
    @At({ "/kc"})
    @Ok("re")
    public String index2(HttpServletRequest req) {
    	//List<Dept> depts=deptService.query(null);
    	//req.setAttribute("dept", depts.get(0));
        User user = ShiroUtils.getSysUser();
        if (!ShiroUtils.isAuthenticated()) {
            return "th:/kc.html";
        }
        user =userService.fetchLinks(user,"roles");
        List<Role> rolelist=user.getRoles();
        String roles=",";
        for(Role role:rolelist) roles+=role.getId()+",";
        user.setRoleIds(roles);
        req.setAttribute("user", user);
        List<Menu> menuList = menuService.getMenuList2(user.getId());
        String perms="";
        for(Menu menu:menuList){
        	if(!menu.getPerms().equals("")) perms+=menu.getPerms()+",";
        }
        req.setAttribute("perms", perms);
        //========================================================
        req.setAttribute("now0", DateUtils.getDateTime());
        //======================"ksid","=","2206"
        List<Mytask> mytasklist= mytaskService.query(Cnd.where("uid","=",user.getId()).desc("starttime"));
        if(mytasklist!=null && mytasklist.size()>0){
        	for(int i=0;i<mytasklist.size();i++){
        		Mytask mytask=mytasklist.get(i);
        		int status=mytask.getStatus();
        		long d1= mytask.getStarttime().getTime();
        		long d2=mytask.getEndtime().getTime();
        		long d0=(new Date()).getTime();
        		
        		if(status==0 && d0>d1 && d0<d2){//考试中
        			mytask.setStatus(1);
        			mytaskService.updateIgnoreNull(mytask);
        		}else if(status==0 && d0>d2){//缺考
        			mytask.setStatus(3);
        			mytaskService.updateIgnoreNull(mytask);
        		}
        		
        	}
        	
        	req.setAttribute("mytasklist", mytasklist);
        }else{
        	req.setAttribute("mytasklist", null);
        }
        return "th:/task1.html";
    }

    @Ok("re")
    @Fail("http:500")
    @At({ "/ewe/zfca"})
    public String zfca(@Param("verify")String verify, @Param("userName") String uid,
                       @Param("strSysDatetime") String strSysDatetime, @Param("jsName")String jsName,
                       HttpSession session, HttpServletRequest req) {
        String verify2=StringUtils.lrwMD5(uid, strSysDatetime, jsName);
        if(!verify2.equals(verify)){
            return ("数字校园验证失败！");//
        }
        User user = userService.fetch(uid);
        if (user == null ) {//
            return ( "请联系主管部门更新系统用户信息");
        }
        try {
            Subject subject = SecurityUtils.getSubject();
            ThreadContext.bind(subject);
            String cardid=user.getCardid();
            subject.login(new UsernamePasswordToken(user.getId(),cardid.substring(cardid.length()-6),false));

        } catch (Exception e) {
            e.printStackTrace();
            return "系统再次验证时有问题";
        }
        user =userService.fetchLinks(user,"roles");
        //ShiroUtils.setSysUser(user);

        List<Role> rolelist=user.getRoles();
        String roles=",";
        for(Role role:rolelist) roles+=role.getId()+",";
        user.setRoleIds(roles);
        req.setAttribute("user", user);
        List<Menu> menuList = menuService.getMenuList2(user.getId());
        String perms="";
        for(Menu menu:menuList){
            if(!menu.getPerms().equals("")) perms+=menu.getPerms()+",";
        }
        req.setAttribute("perms", perms);
        //========================================================
        req.setAttribute("now0", DateUtils.getDateTime());
        //======================
        List<Mytask> mytasklist= mytaskService.query(Cnd.where("uid","=",uid).desc("starttime"));
        if(mytasklist!=null && mytasklist.size()>0){
            for(int i=0;i<mytasklist.size();i++){
                Mytask mytask=mytasklist.get(i);
                int status=mytask.getStatus();
                long d1= mytask.getStarttime().getTime();
                long d2=mytask.getEndtime().getTime();
                long d0=(new Date()).getTime();

                if(status==0 && d0>d1 && d0<d2){//考试中
                    mytask.setStatus(1);
                    mytaskService.updateIgnoreNull(mytask);
                }else if(status==0 && d0>d2){//缺考
                    mytask.setStatus(3);
                    mytaskService.updateIgnoreNull(mytask);
                }

            }

            req.setAttribute("mytasklist", mytasklist);
        }else{
            req.setAttribute("mytasklist", null);
        }
        return  "th:/task1.html";
    }
    @At("/kd")
    @Ok("re")
    public String kd(HttpServletRequest req) {
            return "th:/kd.html";
    }
    /**
     * 系统介绍
     *
     * @return
     */
    @At({"/sys/main"})
    @Ok("th:/main5.html")
    public void main(HttpServletRequest req) {//NutMap
    	User user = ShiroUtils.getSysUser();
    	List<String> qlist=StringUtils.getStrRowValues(dao, Sqls.create("SELECT distinct problem_id FROM solution  WHERE username='"+user.getId()+"' AND verdict=5"));
    	//List<Solution> qlist=solutionService.query("^(problem_id|uid|verdict)$",Cnd.where("uid","=",user.getId()).and("verdict", "=", 5));
    	String ids=StringUtils.getSeqRowValue(dao,  Sqls.create("SELECT distinct problem_id FROM solution  WHERE username='"+user.getId()+"' AND verdict=5"));
    	req.setAttribute("acmed", qlist);
    	req.setAttribute("acids", ids);
    	req.setAttribute("now0", DateUtils.getDateTime());
        //return NutMap.NEW().setv("now0", DateUtils.getDateTime());
    }

    /**
     * NB自身初始化完成后会调用这个方法
     */
    public void init() {
    	Mvcs.X_POWERED_BY = "fcre2.0";
        // 环境检查
        if (!Charset.defaultCharset().name().equalsIgnoreCase(Encoding.UTF8)) {
            log.warn("This project must run in UTF-8, pls add -Dfile.encoding=UTF-8 to JAVA_OPTS");
        }
        // 初始化系统变量
        Globals.getInstance();
        initSysTask(ioc);
        /**
         * 自定义EL表达式
         * 文档
         * http://nutzam.com/core/el/overview.html
         */
        CustomMake.me().register("array2str", new RunMethod(){
            @Override
            public Object run(List<Object> fetchParam) {
                String tmp = JSON.toJSONString(fetchParam);
                return tmp;
            }
            @Override
            public String fetchSelf() {
                return "array2str";
            }
        });
        // 创建数据库
        Daos.createTablesInPackage(dao, "io.nutz.nutzsite", false);
    }

    /**
     * 清空定时任务 否则会存在僵尸java进程
     */
    public void depose() {
        log.info("depose AsyncManager Task");
        AsyncManager.me().shutdown();

        log.info("depose Sys Task");
        QuartzManager quartzManager = ioc.get(QuartzManager.class);
        quartzManager.clear();
        // 解决quartz有时候无法停止的问题
        try {
            ioc.get(Scheduler.class).shutdown(true);
        } catch (Exception e) {

        }
        // 非mysql数据库,或多webapp共享mysql驱动的话,以下语句删掉
        try {
            Mirror.me(Class.forName("com.mysql.jdbc.AbandonedConnectionCleanupThread")).invoke(null, "shutdown");
        } catch (Throwable e) {

        }
        // 解决com.alibaba.druid.proxy.DruidDriver和com.mysql.jdbc.Driver在reload时报warning的问题
        // 多webapp共享mysql驱动的话,以下语句删掉
        Enumeration<Driver> en = DriverManager.getDrivers();
        while (en.hasMoreElements()) {
            try {
                Driver driver = en.nextElement();
                String className = driver.getClass().getName();
                log.debug("deregisterDriver: " + className);
                DriverManager.deregisterDriver(driver);
            }
            catch (Exception e) {
            }
        }
        try {
            MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
            ObjectName objectName = new ObjectName("com.alibaba.druid:type=MockDriver");
            if (mbeanServer.isRegistered(objectName)) {
                mbeanServer.unregisterMBean(objectName);
            }
            objectName = new ObjectName("com.alibaba.druid:type=DruidDriver");
            if (mbeanServer.isRegistered(objectName)) {
                mbeanServer.unregisterMBean(objectName);
            }
        } catch (Exception ex) {

        }
    }

    /**
     * 初始化 定时任务
     * @param ioc
     */
    @Slog(tag="定时任务", after="启动满足条件的定时任务")
    private void initSysTask(Ioc ioc) {
        QuartzManager quartzManager = ioc.get(QuartzManager.class);
        TaskService taskService = ioc.get(TaskService.class);
        quartzManager.clear();
        //任务状态1正常0暂停
        List<Task> taskList = taskService.query( Cnd.where("status", "=", true));
        for (Task sysTask : taskList) {
            try {
                QuartzJob qj = new QuartzJob();
                qj.setJobName(sysTask.getId());
                qj.setJobGroup(sysTask.getId());
                qj.setClassName(sysTask.getJobClass());
                qj.setCron(sysTask.getCron());
                qj.setComment(sysTask.getNote());
                qj.setDataMap(sysTask.getData());
                quartzManager.add(qj);
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }
    }
    /*J2cache 
    //@Inject
    protected CacheChannel cacheChannel;
    *//**
     * 添加缓存
     * @param region
     * @param name
     * @param val
     * @return
     *//*
    @At
    @Ok("raw")
    public String put(@Param("region") String region,@Param("name") String name,@Param("val") String val){
        cacheChannel.set(region,name,val);
        return "success";
    }
    *//**
     * 取缓存值
     * @param region
     * @param name
     * @return
     *//*
    @At
    @Ok("raw")
    public Object get(@Param("region") String region, @Param("name") String name){
        CacheObject cacheObject = cacheChannel.get(region, name);
        if(cacheObject!= null){
            return  cacheObject.getValue();
        }
        return "空";
    }
    *//**
     * 清除缓存对象
     * @param region
     * @param name
     * @return
     *//*
    @At
    @Ok("raw")
    public Object evict(@Param("region")String region,@Param("name")String name){
       cacheChannel.evict(region, name);
       return "ok";
    }
    *//**
     * 强制清除缓存
     * @param region
     * @return
     *//*
    @At
    @Ok("raw")
    public Object clear(@Param("region") String region){
        cacheChannel.clear(region);
        return true;
    }*/
    /*Caffine Cache*/
    /*@Ok("raw")
	@At("/time/now")
	@Cache
	public String now() {
		return "刷新试试，我动算我输，╭(╯^╰)╮ "+System.currentTimeMillis();
	}
	
	@Ok("raw")
    @At("/time/live3s")
    @Cache("live3s")
	public String live10s() {
	    return "刷新试试，我每3秒变一下，俗称 “活不过3秒”，╭(╯^╰)╮ "+System.currentTimeMillis();
	}
	
	@Ok("raw")
	@At("/time/idel3s")
	@Cache("idel3s")
	public String idel10s() {
	    return "3秒不续命，我就玩完 ╭(╯^╰)╮ "+System.currentTimeMillis();
	}*/
}
